"""
Security and Authentication
JWT token handling and password utilities
"""

from datetime import datetime, timedelta
from typing import Optional, Union
# from jose import JWTError, jwt
from jose import jwt
from jose.exceptions import JWTError
from passlib.context import CryptContext
from fastapi import HTTPException, status
import logging

from app.core.config import settings

logger = logging.getLogger(__name__)

# Password context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """Verify a password against its hash"""
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    """Generate password hash"""
    return pwd_context.hash(password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """Create JWT access token"""
    to_encode = data.copy()

    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)

    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)

    return encoded_jwt


def verify_token(token: str) -> Optional[str]:
    """Verify and decode JWT token"""
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        user_id: str = payload.get("sub")

        if user_id is None:
            return None

        return user_id
    except JWTError as e:
        logger.warning(f"JWT verification failed: {e}")
        return None


class EnvironmentAwareAuth:
    """Environment-aware authentication middleware"""

    @staticmethod
    def get_current_user_dev(token: Optional[str] = None) -> dict:
        """Development environment authentication - allows default user"""
        if settings.ENVIRONMENT == "production":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Production environment requires valid authentication"
            )

        # Development environment - return default user if no token provided
        if not token:
            return {
                "user_id": "dev-user-123",
                "email": "dev@example.com",
                "name": "Development User"
            }

        # If token provided, try to verify it
        user_id = verify_token(token)
        if user_id:
            return {
                "user_id": user_id,
                "email": f"{user_id}@example.com",
                "name": f"User {user_id}"
            }

        # Invalid token in dev mode - still allow default user
        logger.warning("Invalid token provided in development mode, using default user")
        return {
            "user_id": "dev-user-123",
            "email": "dev@example.com",
            "name": "Development User"
        }

    @staticmethod
    def get_current_user_prod(token: str) -> dict:
        """Production environment authentication - requires valid token"""
        if settings.ENVIRONMENT != "production":
            # For non-production, delegate to dev mode
            return EnvironmentAwareAuth.get_current_user_dev(token)

        user_id = verify_token(token)
        if not user_id:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Could not validate credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )

        return {
            "user_id": user_id,
            "email": f"{user_id}@example.com",
            "name": f"User {user_id}"
        }


def get_current_user(authorization: Optional[str] = None) -> dict:
    """
    Environment-aware current user extraction
    Supports both production and development modes
    """
    # Extract token from authorization header
    token = None
    if authorization and authorization.startswith("Bearer "):
        token = authorization.split(" ")[1]

    if settings.ENVIRONMENT == "production":
        return EnvironmentAwareAuth.get_current_user_prod(token)
    else:
        return EnvironmentAwareAuth.get_current_user_dev(token)